package de.uhlesoluschns.opensearch.ui;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;

import android.app.Activity;
import android.app.Dialog;
import android.app.SearchManager;
import android.app.AlertDialog.Builder;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView.OnEditorActionListener;
import de.uhlesoluschns.opensearch.OpenSearch;
import de.uhlesoluschns.opensearch.R;
import de.uhlesoluschns.opensearch.OpenSearch.Provider;
import de.uhlesoluschns.opensearch.OpenSearch.Suggestion;
import de.uhlesoluschns.opensearch.provider.SuggestionsAdapter;

public class SearchBox extends Activity implements OnClickListener,
		OnItemClickListener, DialogInterface.OnClickListener, TextWatcher {

	private static final int DIALOG_PROVIDERS = 0;

	private AutoCompleteTextView searchInput;
	private ImageButton providerButton;
	private ImageButton searchButton;
	private LinearLayout searchBar;

	private int engineId;
	private String engineSearchUrl;
	private String engineInputEncoding;
	private boolean hasSuggestions;

	private SuggestionsAdapter suggestionsAdapter;

	private SharedPreferences sharedPreferences;

	private Cursor selectedProvider;
	private Cursor providers;

	private boolean hasInitialSuggestions;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.search_box);
		providers = managedQuery(Provider.CONTENT_URI, new String[] {
				Provider.COL_ID, Provider.COL_SHORT_NAME, Provider.COL_ICON },
				null, null, Provider.COL_SHORT_NAME);
		sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		initUI();
	}
	
	@Override
	protected void onStart() {
		super.onStart();
		if (searchInput != null) {
			searchInput.setText(null);
		}
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		initSearchProvider(
				getIntent().getData(), 
				(String) getIntent().getStringExtra(SearchManager.QUERY));

		JSONArray suggestions = null;
		if(getIntent().hasExtra(SearchManager.EXTRA_DATA_KEY)) {
			String json = getIntent().getStringExtra(SearchManager.EXTRA_DATA_KEY);
			try {
				suggestions = new JSONArray(json);
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		initSearchSuggestions(suggestions);
	}
	
	@Override
	protected void onPostResume() {
		super.onPostResume();
		new Handler().postDelayed(new Runnable() {
			public void run() {
				if(hasInitialSuggestions) {
					searchInput.showDropDown();
				} else {
					InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
					inputManager.showSoftInput(searchInput, 0);
				}
			}
		}, 500);
	}
	
	private void initUI() {
		// for exiting the app
		searchBar = (LinearLayout) findViewById(R.id.search_bar);
		searchBar.setOnClickListener(this);
		// this one is just to prevent exiting if search_plate is clicked
		findViewById(R.id.search_plate).setOnClickListener(this);

		searchInput = (AutoCompleteTextView) findViewById(R.id.search_src_text);
		searchInput.addTextChangedListener(this);
		searchInput.setOnItemClickListener(this);
		searchInput.setOnEditorActionListener(new OnEditorActionListener() {
			@Override
			public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
				launchSearch();
				return true;
			}
		});

		providerButton = (ImageButton) findViewById(R.id.search_provider);
		providerButton.setOnClickListener(this);
		searchButton = (ImageButton) findViewById(R.id.search_go);
		searchButton.setOnClickListener(this);
	}
	
	private void initSearchProvider(Uri uri, String query) {
		String id = null;
		if (uri != null) {
			id = uri.getLastPathSegment();
		}

		if (id == null || Provider.PATH.equals(id)) {
			id = "" + sharedPreferences.getInt(Preferences.SELECTED_PROVIDER, -1);
		}

		selectedProvider = managedQuery(Provider.CONTENT_URI, new String[] {
				Provider.COL_ID, Provider.COL_SHORT_NAME, Provider.COL_ICON,
				Provider.COL_SEARCH_URL, Provider.COL_SUGGESTION_URL,
				Provider.COL_INPUT_ENCODING }, Provider.COL_ID + "=?",
				new String[] { id }, null);
		if (selectedProvider.moveToFirst()) {
			engineId = selectedProvider.getInt(0);
			searchInput.setText(query);
			searchInput.setHint(selectedProvider.getString(1));
			byte[] data = selectedProvider.getBlob(2);
			try {
				providerButton.setImageBitmap(BitmapFactory.decodeByteArray(
						data, 0, data.length));
			} catch (Exception e) {
				providerButton.setImageBitmap(null);
			}
			engineSearchUrl = selectedProvider.getString(3);
			hasSuggestions = !selectedProvider.isNull(4);
			engineInputEncoding = selectedProvider.getString(5);
			
		}
	}

	private void initSearchSuggestions(JSONArray suggestions) {
		// attach the suggestions adapter
		suggestionsAdapter = null;
		if (hasSuggestions) {
			suggestionsAdapter = new SuggestionsAdapter(this,
					android.R.layout.simple_dropdown_item_1line, null,
					new String[] { Suggestion.COL_SUGGESTION },
					new int[] { android.R.id.text1 }, engineId, suggestions);
		} else if(sharedPreferences.getBoolean(Preferences.AOS_SUGGESTIONS, false)) {
			//add android-open-search provider suggestions
			suggestionsAdapter = new SuggestionsAdapter(this, android.R.layout.simple_dropdown_item_1line, null,
					new String [] { Suggestion.COL_SUGGESTION},
					new int [] { android.R.id.text1 }, Integer.MIN_VALUE + engineId, null);
		}
		searchInput.setAdapter(suggestionsAdapter);
		hasInitialSuggestions = suggestions != null;
	}

	private void launchSearch() {
		String searchText = searchInput.getText().toString();
		final String query;
		if (TextUtils.getTrimmedLength(searchText) < 1) {
			return;
		}
		try {
			query = URLEncoder.encode(searchText, engineInputEncoding);
		} catch (UnsupportedEncodingException e) {
			Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG);
			return;
		}

		Uri searchUri = Uri.parse(String.format(engineSearchUrl, query));
		Intent search = new Intent(Intent.ACTION_VIEW, searchUri);
		search.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		try {
			startActivity(search);
		} catch(ActivityNotFoundException e) {
			//happens if we have a context:// or market:// uri
			Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
		}
		
		if(!hasSuggestions && sharedPreferences.getBoolean(Preferences.AOS_POST_SEARCH, false)) {
			new Thread(new Runnable() {
				public void run() {
					try {
						HttpClient client = new DefaultHttpClient();
						HttpPost post = new HttpPost(OpenSearch.OPEN_SEARCH_SUGGESTION_URL);
						List<NameValuePair> params = new ArrayList<NameValuePair>();
						
						//decode query because it has already been encoded and will automatically be encoded by UrlEncodedFormEntity
						params.add(new BasicNameValuePair("q", URLDecoder.decode(query, engineInputEncoding)));
						params.add(new BasicNameValuePair("url", engineSearchUrl));
						
						UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params);
						entity.setContentEncoding(OpenSearch.OPEN_SEARCH_SUGGESTION_ENCODING);
						post.setEntity(entity);
						client.execute(post);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}).start();
		}
		finish();
	}

	private void listProviders() {
		showDialog(DIALOG_PROVIDERS);
	}

	/*
	 * UI Event Listener implementations
	 */
	public void onClick(View v) {
		if (v == searchBar) {
			finish();
		} else if (v == searchButton) {
			launchSearch();
		} else if (v == providerButton) {
			listProviders();
		}
	}

	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		if(sharedPreferences.getBoolean("suggestions_launch_search", true)) {
			launchSearch();
		}
	}

	public void onClick(DialogInterface dialog, int which) {
		Editor editor = sharedPreferences.edit();
		providers.moveToPosition(which);
		editor.putInt(Preferences.SELECTED_PROVIDER, providers.getInt(0));
		editor.commit();
		initSearchProvider(null, null);
		initSearchSuggestions(null);
		dialog.dismiss();
	}

	public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
	
	public void onTextChanged(CharSequence s, int start, int before, int count) {
		 boolean enabled = TextUtils.getTrimmedLength(searchInput.getText()) != 0;
		 searchButton.setEnabled(enabled);
		 searchButton.setFocusable(enabled);
		 searchInput.setListSelection(-1);
	}
	
	public void afterTextChanged(Editable s) {}

	/*
	 * Overrides
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		Builder builder = new Builder(this);
		switch (id) {
		case DIALOG_PROVIDERS:
			builder.setTitle("Search Providers");
			builder.setCancelable(true);
			providers.requery();
			int selectedId = sharedPreferences.getInt(Preferences.SELECTED_PROVIDER, -1);
			int which = -1;
			while (providers.moveToNext()) {
				if (selectedId == providers.getInt(0)) {
					which = providers.getPosition();
					break;
				}
			}
			builder.setSingleChoiceItems(providers, which,
					Provider.COL_SHORT_NAME, this);
			break;
		default:
			return null;
		}
		return builder.create();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.search_box_options, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_add_provider:
			Intent intent = new Intent(Intent.ACTION_VIEW,
					OpenSearch.ADD_PROVIDER_URI);
			intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			startActivity(intent);
			return true;
		case R.id.menu_add_advanced:
			startActivity(new Intent(this, AddAdvanced.class));
			return true;
		case R.id.menu_delete_provider:
			getContentResolver().delete(Provider.CONTENT_URI,
					Provider.COL_ID + "=?", new String[] { "" + engineId });
			showDialog(DIALOG_PROVIDERS);
			return true;
		case R.id.menu_preferences:
			startActivity(new Intent(this, Preferences.class));
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}
}
